import json
from datetime import datetime
from decimal import Decimal
from django import http
from django.contrib.auth.mixins import LoginRequiredMixin
from django.core.paginator import Paginator
from django.db import transaction
from django.http import HttpResponse
from django.http import JsonResponse
from django.shortcuts import render
from django.views import View
from django_redis import get_redis_connection
from apps.goods.models import SKU
from apps.orders.models import OrderInfo, OrderGoods
from apps.users.models import Address
from utils.response_code import RETCODE


# 结算订单

class OrderSettlementView(LoginRequiredMixin, View):
    # 提供订单结算页面
    def get(self, request):
        # 显示界面render
        # 获取 改用户收货地址
        # 从redis中获取数据
        user = request.user
        try:
            addresses = Address.objects.filter(user=user,is_deleted=False)
        except:
            addresses = None
            # 链接数据库
        redis_client = get_redis_connection("carts")
        # 取该用户的商品
        carts_data = redis_client.hgetall(user.id)
        # 转换redis取出的数据格式
        carts_dict = {}
        for key,value in carts_data.items():
            sku_key = int(key.decode())
            sku_dict = json.loads(value.decode())
            if sku_dict["selected"]:
                carts_dict[sku_key]=sku_dict
        # 查找商品对象
        skus = SKU.objects.filter(id__in=carts_dict.keys())
        # 计算金额
        total_count = 0
        total_amount = Decimal('0.00')
        for sku in skus:
            # 商品个数
            sku.count = carts_dict[sku.id]["count"]
            # 小计
            sku.amount = sku.price*sku.count
            # 总数量
            total_count += sku.count
            # 所有商品总价格
            total_amount += sku.price*carts_dict[sku.id]["count"]
        # 运费
        freight = Decimal('10.00')
        # 4.构建前端显示的数据

        context = {
            'addresses': addresses,
            'skus': skus,
            'total_count': total_count,
            'total_amount': total_amount,
            'freight': freight,
            'payment_amount': total_amount + freight,
            'default_address_id': user.default_address_id,
            'username':request.user.username
        }
        return render(request, 'place_order.html', context)

# 提交订单

class OrderCommitView(LoginRequiredMixin, View):

    def post(self, request):
        # 接受参数
        # 获取当前要保存的订单数据
        # 将请求体参数转成字典
        json_dict = json.loads(request.body.decode())
        # 收货地址
        address_id = json_dict.get('address_id')
        # 支付方式
        pay_method = json_dict.get('pay_method')
        # 校验参数
        if not all([address_id, pay_method]):
            return http.HttpResponseForbidden('缺少必传参数')
        # 判断address_id是否合法
        try:
            address = Address.objects.get(id=address_id)
        except Exception:
            return http.HttpResponseForbidden('参数address_id错误')
        # 判断pay_method是否合法
        if pay_method not in [OrderInfo.PAY_METHODS_ENUM['CASH'], OrderInfo.PAY_METHODS_ENUM['ALIPAY']]:
            return http.HttpResponseForbidden('参数pay_method错误')
            # --------开启事务--------
        with transaction.atomic():
            # --------事物保存点（事务开始的标记）--------
            save_id = transaction.savepoint()
            try:
                # 生成订单号---时间戳+9位+user_id
                user = request.user
                # 拼接订单号
                # datetime.now()取当前时间带十分秒的   .strftime("%Y%m%d%H%m%s")按照这个格式显示拼接
                order_id = datetime.now().strftime("%Y%m%d%H%m%s")+("%09d" % user.id)
                # 创建订单表数据(1个)
                order = OrderInfo.objects.create(
                    order_id=order_id,  #订单号
                    user=user,
                    address=address,
                    total_count=0,  # 总数量
                    total_amount=Decimal('0'),  # 总价格
                    freight=Decimal('10.00'),   # 运费
                    pay_method=pay_method,  # 支付方式
                    # 待支付  如果支付方式为支付宝  为待发货
                    status=OrderInfo.ORDER_STATUS_ENUM['UNPAID'] if pay_method == OrderInfo.PAY_METHODS_ENUM['ALIPAY'] else
                    OrderInfo.ORDER_STATUS_ENUM['UNSEND']   #状态
                )
                # 从购物车取出选中的商品
                redis_client = get_redis_connection("carts")
                carts_data = redis_client.hgetall(user.id)
                carts_dict = {}
                for key,value in carts_data.items():
                    sku_id = int(key.decode())
                    sku_dict = json.loads(value.decode())
                    if sku_dict["selected"]:
                        carts_dict[sku_id] = sku_dict   #生成商品的字典{sku_id{sku_dict}}
                sku_ids = carts_dict.keys()     #取所有的商品id
                for sku_id in sku_ids:
                    while True:
                        sku = SKU.objects.get(id=sku_id)    #取商品对象
                        original_stock = sku.stock  #记录老库存
                        original_sales = sku.sales#记录老销量
                        cart_count = carts_dict[sku_id]["count"]    #取购物车中对应商品个数
                        if cart_count > sku.stock:  #如果购买个数大于库存个数
                            # --------事物回滚--------
                            transaction.savepoint_rollback(save_id)
                            # 失败时跳出
                            return JsonResponse({'code': RETCODE.STOCKERR, 'errmsg': '库存不足'})
                        # 模拟用户接近同时下单
                        # import time
                        # time.sleep(10)
                        # # sku减少库存, 增加销量
                        # sku.stock -= cart_count     #商品库存将-=购买个数
                        # sku.sales += cart_count     #商品销量 += 购买个还素
                        # sku.save()
                            # 使用乐观锁 更新库存量
                        new_stock = original_stock - cart_count
                        new_sales = original_sales + cart_count
                        # 加乐观锁   定时更新  进入页面记录老库存到提交订单时重新访问数据库 有修改 则就不让下单（修改数据库）
                        result = SKU.objects.filter(id=sku_id, stock=original_stock).update(
                            stock=new_stock,sales=new_sales)
                        # 如果库存充足的 购买失败了  继续购买知道成功位置（或库存不足失败）
                        if result == 0:
                            continue
                        # spu销量增加
                        sku.spu.sales +=cart_count  #spu销量 += 购买个还素
                        sku.spu.save()
                    # 创建订单商品数据(n个)
                        OrderGoods.objects.create(
                            # 订单号
                            order_id=order_id,
                            sku=sku,
                            count=cart_count,
                            price=sku.price,
                        )
                        # 总个数  动态添加属性不全第一张表的数据
                        order.total_count += cart_count
                        # 总金额
                        order.total_amount += sku.price*cart_count
                        # 下单成功
                        break
                # 加运费的总金额
                order.total_amount += order.freight
                order.save()
            except:
                # --------事物回滚--------
                transaction.savepoint_rollback(save_id)
                return JsonResponse({'code': RETCODE.OK, 'errmsg': '下单失败'})
            # --------提交事物(没问题)--------
            transaction.savepoint_commit(save_id)
        # 清除购物车已经结算过的商品
        # 将对象的所有k给前面后删除   *carts_dict可以直接遍历字典中的所有key
        redis_client.hdel(user.id, *carts_dict)
        # 返回响应结果
        return JsonResponse({'code': RETCODE.OK, 'errmsg': '下单成功', 'order_id': order.order_id})

# 展示提交成功界面

class OrderSuccessView(LoginRequiredMixin,View):

    def get(self, request):
        order_id = request.GET.get('order_id')
        payment_amount = request.GET.get('payment_amount')
        pay_method = request.GET.get('pay_method')

        context = {
            'order_id': order_id,
            'payment_amount': payment_amount,
            'pay_method': pay_method
        }
        return render(request, 'order_success.html', context)

# 订单页显示

class OrderInfoView(LoginRequiredMixin,View):
    def get(self,request,page_num):
        # # 接受参数
        try:
            page_num = int(page_num)
        except:
            return http.HttpResponseForbidden("page_num参数有误")
        # 校验参数
        user = request.user
        # 取用户订单表的所有数据按时间倒序
        orders = user.orderinfo_set.all().order_by('-create_time')
        for order in orders:
            # 获取订单状态名字
            # 将日期按照格式转换成字符串
            today_str = order.create_time.strftime('%Y-%m-%d %H:%M:%S')  # 输出字符串
            # 将字符串再转换成日期格式
            today_data = datetime.strptime(today_str, '%Y-%m-%d %H:%M:%S')
            order.create_time = today_data
            order.status_name = OrderInfo.ORDER_STATUS_CHOICES[order.status-1][1]
            # 获取支付状态名
            order.pay_method_name = OrderInfo.PAY_METHOD_CHOICES[order.pay_method-1][1]
            order.sku_list = []
            # 取出所有订单所有商品
            order_goods = order.skus.all()
            for goods in order_goods:
                # 取商品对象
                print(goods,type(goods))
                sku = goods.sku
                # 动态添加属性
                sku.count = goods.count
                sku.amount = sku.price*sku.count
                order.sku_list.append(sku)
        try:
            # 创建分页器：每页N条记录
            paginator = Paginator(orders, 3)
            # 获取每页商品数据
            page_orders = paginator.page(page_num)
            # 获取列表页总页数
            total_page = paginator.num_pages
        except :
            # 如果page_num不正确，默认给用户404
            return http.HttpResponseNotFound('该订单不存在')
        # 装配前端数据
        context = {
            # 每页显示的内容
            "page_orders": page_orders,
            # 总页数
            'total_page': total_page,
            # 当前页
            'page_num': page_num,
        }
        # print(context)
        return render(request,'user_center_order.html',context)

# 订单评价
class OrderCommentView(LoginRequiredMixin, View):
    def get(self,request):
        order_id = request.GET.get("order_id")
        # print(order_id)
        goodss = OrderGoods.objects.filter(order_id=order_id)
        uncomment_goods_list=[]
        for goods in goodss:
                good_dict = {
                    'order_id': goods.order_id,
                    'sku_id': goods.sku.id,
                    'name': goods.sku.name,
                    'price': str(goods.price),
                    'default_image_url': goods.sku.default_image.url,
                    'comment': goods.comment,
                    'score': goods.score,
                    'is_anonymous': str(goods.is_anonymous),
                }
                uncomment_goods_list.append(good_dict)
        context = {'uncomment_goods_list':uncomment_goods_list}
        return render(request,'goods_judge.html',context)
        # 链接数据库该地址
    def post(self,request):
        json_str = request.body.decode()
        req_data = json.loads(json_str)
        OrderGoods.objects.filter(order_id=req_data['order_id'],sku_id=req_data['sku_id']).update(
            score = req_data['score'],
            comment = req_data['comment'],
            is_anonymous = req_data['is_anonymous'],
            is_commented = True,
        )
        orderinfo = OrderInfo.objects.get(user_id=request.user.id,order_id=req_data['order_id'])
        orderinfo.status=5
        orderinfo.save()
        return JsonResponse({'code': RETCODE.OK,'errmsg': '评价成功'})

# 详情页展示

class CommentView(LoginRequiredMixin, View):
    def get(self,request,sku_id):
        skus = SKU.objects.get(id=sku_id)
        goods = skus.ordergoods_set.all()
        comment_list=[]
        for good in goods:
            if good.is_commented == 1:
                good_data = {
                    'username' : good.order.user.username,
                    "comment": good.comment,
                    "score": good.score,
                }
                comment_list.append(good_data)
        # print(comment_list)
        return JsonResponse(
        {"code": "0","errmsg": "OK","comment_list": comment_list})